package com.yunpeng.aidevice.biz.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yunpeng.aidevice.biz.service.IDeviceBizService;
import com.yunpeng.aidevice.biz.service.INoticeBizService;
import com.yunpeng.aidevice.common.constant.QueryConstants;
import com.yunpeng.aidevice.common.dto.query.DeviceQueryDTO;
import com.yunpeng.aidevice.common.dto.save.DeviceSaveDTO;
import com.yunpeng.aidevice.common.enums.DeviceUploadDataStateEnum;
import com.yunpeng.aidevice.common.enums.ResultCodeEnum;
import com.yunpeng.aidevice.common.enums.UserStateEnum;
import com.yunpeng.aidevice.common.vo.AppUpdateInfoVO;
import com.yunpeng.aidevice.common.vo.SimpleEntityVO;
import com.yunpeng.aidevice.common.vo.device.DeviceAppDetailVO;
import com.yunpeng.aidevice.common.vo.device.DeviceDetailVO;
import com.yunpeng.aidevice.common.vo.user.UserAppDetailVO;
import com.yunpeng.aidevice.dao.constant.DictionariesConstant;
import com.yunpeng.aidevice.dao.model.entity.DeviceDO;
import com.yunpeng.aidevice.dao.model.entity.UserDO;
import com.yunpeng.aidevice.dao.model.record.NoticeRuleParameterDO;
import com.yunpeng.aidevice.dao.model.record.RecordDO;
import com.yunpeng.aidevice.dao.service.*;
import com.yunpeng.common.dto.Result;
import com.yunpeng.common.enums.QueryOperatorEnum;
import com.yunpeng.common.exception.BizException;
import com.yunpeng.common.paging.PagingQueryDTO;
import com.yunpeng.common.paging.query.QueryParam;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * DeviceBizServiceImpl
 *
 * @author : Moore(hemw)
 * @date : 2020-04-27
 */
@Service
public class DeviceBizServiceImpl implements IDeviceBizService {

    @Resource
    private IListQueryService listQueryService;

    @Resource
    private IDeviceService deviceService;

    @Resource
    private IOrganizationService organizationService;

    @Resource
    private INoticeRuleService noticeRuleService;

    @Resource
    private IUserService userService;

    @Resource
    private IDictionariesService dictionariesService;

    @Resource
    private INoticeBizService noticeBizService;

    @Resource
    private IMerchantService merchantService;

    @Override
    /**
     * 设备商户端列表
     *
     * @param deviceQueryDTO
     * @return
     */
    public Result<PagingQueryDTO> queryDeviceList4Merchant(DeviceQueryDTO deviceQueryDTO) {
        PagingQueryDTO pagingQueryDTO = new PagingQueryDTO();
        List<QueryParam> queryParams = new ArrayList<>();
        LinkedHashMap<String, String> orderByMap = new LinkedHashMap<>(16);
        if (StringUtils.isNotBlank(deviceQueryDTO.getDeviceNumber())) {
            queryParams.add(QueryParam.quickSetQueryParam("number",
                    deviceQueryDTO.getDeviceNumber(), QueryOperatorEnum.EQUALS));
        }
        if (StringUtils.isNotBlank(deviceQueryDTO.getDeviceName())) {
            queryParams.add(QueryParam.quickSetQueryParam("name",
                    deviceQueryDTO.getDeviceName(), QueryOperatorEnum.LEFT_LIKE));
        }
        if (StringUtils.isNotBlank(deviceQueryDTO.getInstallLocation())) {
            queryParams.add(QueryParam.quickSetQueryParam("install_location",
                    deviceQueryDTO.getInstallLocation(), QueryOperatorEnum.LEFT_LIKE));
        }
        if (StringUtils.isNotBlank(deviceQueryDTO.getDeviceId())) {
            queryParams.add(QueryParam.quickSetQueryParam("device_id",
                    deviceQueryDTO.getDeviceId(), QueryOperatorEnum.EQUALS));
        }
        if (StringUtils.isNotBlank(deviceQueryDTO.getState())) {
            queryParams.add(QueryParam.quickSetQueryParam("state",
                    deviceQueryDTO.getState(), QueryOperatorEnum.EQUALS));
        }
        if (deviceQueryDTO.getInstallDateStart() != null) {
            queryParams.add(QueryParam.quickSetQueryParam("install_time",
                    deviceQueryDTO.getInstallDateStart(), QueryOperatorEnum.GREATER_THAN));
        }
        if (deviceQueryDTO.getInstallDateEnd() != null) {
            queryParams.add(QueryParam.quickSetQueryParam("install_time",
                    deviceQueryDTO.getInstallDateEnd(), QueryOperatorEnum.LESS_THAT_AND_EQUALS));
        }
        //商户
        queryParams.add(QueryParam.quickSetQueryParam("merchant_code",
                deviceQueryDTO.getMerchantCode(), QueryOperatorEnum.EQUALS));
        //租户
        queryParams.add(QueryParam.quickSetQueryParam("tenant_code",
                deviceQueryDTO.getTenantCode(), QueryOperatorEnum.EQUALS));
        queryParams.add(QueryParam.quickSetQueryParam("flag", 1, QueryOperatorEnum.EQUALS));
        orderByMap.put("t.update_time", "desc");
        orderByMap.put("t.id", "desc");
        pagingQueryDTO.setCurrentPage(deviceQueryDTO.getCurrentPage());
        pagingQueryDTO.setPageSize(deviceQueryDTO.getPageSize());
        pagingQueryDTO.setConditionList(queryParams);
        pagingQueryDTO.setSortColumnMap(orderByMap);
        PagingQueryDTO resultData = listQueryService.query(pagingQueryDTO, QueryConstants.QUERY_DEVICE_LIST_4_MERCHANT, null);
        return Result.success(resultData);
    }

    @Override
    /**
     * 新增设备
     *
     * @param deviceSaveDTO 设备信息
     * @param operatorCode  操作人代码
     * @return
     */
    public Result<Void> addNewDevice(DeviceSaveDTO deviceSaveDTO, String operatorCode) {
        if (deviceService.addNew(deviceSaveDTO, operatorCode)) {
            return Result.success();
        }
        return Result.fail(ResultCodeEnum.SAVE_DATA_FAILED);
    }

    @Override
    /**
     * 设备详情
     *
     * @param deviceCode   设备代码
     * @param merchantCode 商户代码
     * @param tenantCode   租户代码
     * @return
     */
    public Result<DeviceDetailVO> deviceDetail(String deviceCode, String merchantCode, String tenantCode) {
        DeviceDO deviceDO = deviceService.getByCode(deviceCode, merchantCode, tenantCode);
        if (deviceDO == null) {
            throw new BizException(ResultCodeEnum.NOT_EXISTS_DATA_FAILED, "无此设备");
        }
        DeviceDetailVO deviceDetailVO = new DeviceDetailVO();
        deviceDetailVO.setDeviceCode(deviceDO.getCode());
        deviceDetailVO.setDeviceNumber(deviceDO.getNumber());
        deviceDetailVO.setDeviceName(deviceDO.getName());
        deviceDetailVO.setInstallDate(deviceDO.getInstallTime());
        deviceDetailVO.setInstallLocation(deviceDO.getInstallLocation());
        deviceDetailVO.setState(deviceDO.getState());
        deviceDetailVO.setDeviceId(deviceDO.getDeviceId());
        deviceDetailVO.setOrgCodes(organizationService.getRelationOrgCodesByDevice(deviceDO.getCode()));
        return Result.success(deviceDetailVO);
    }

    @Override
    /**
     * 更新设备信息
     *
     * @param deviceSaveDTO 设备信息
     * @param operatorCode  操作人代码
     * @return
     */
    public Result<Void> updateDevice(DeviceSaveDTO deviceSaveDTO, String operatorCode) {
        if (deviceService.updateDevice(deviceSaveDTO, operatorCode)) {
            return Result.success();
        }
        return Result.fail(ResultCodeEnum.SAVE_DATA_FAILED);
    }

    @Override
    /**
     * 启用设备
     *
     * @param deviceCode   设备代码
     * @param operatorCode 操作人代码
     * @param merchantCode 商户代码
     * @param tenantCode   租户代码
     * @return
     */
    public Result<Void> enableDevice(String deviceCode, String operatorCode, String merchantCode, String tenantCode) {
        if (deviceService.enableDisableDevice(false, deviceCode, operatorCode, merchantCode, tenantCode)) {
            return Result.success();
        }
        return Result.fail(ResultCodeEnum.SAVE_DATA_FAILED);
    }

    @Override
    /**
     * 禁用设备
     *
     * @param deviceCode   设备代码
     * @param operatorCode 操作人代码
     * @param merchantCode 商户代码
     * @param tenantCode   租户代码
     * @return
     */
    public Result<Void> disableDevice(String deviceCode, String operatorCode, String merchantCode, String tenantCode) {
        if (deviceService.enableDisableDevice(true, deviceCode, operatorCode, merchantCode, tenantCode)) {
            return Result.success();
        }
        return Result.fail(ResultCodeEnum.SAVE_DATA_FAILED);
    }

    @Override
    /**
     * 删除设备
     *
     * @param deviceCode   设备代码
     * @param merchantCode 商户代码
     * @param tenantCode   租户代码
     * @return
     */
    public Result<Void> deleteDevice(String deviceCode, String merchantCode, String tenantCode) {
        if (deviceService.deleteDevice(deviceCode, merchantCode, tenantCode)) {
            return Result.success();
        }
        return Result.fail(ResultCodeEnum.SAVE_DATA_FAILED);
    }

    @Override
    /**
     * 设备下拉数据
     *
     * @param merchantCode
     * @param tenantCod
     * @return
     */
    public Result<List<SimpleEntityVO>> dropDownList(String merchantCode, String tenantCod) {
        List<DeviceDO> deviceDOList = deviceService.getByMerchant(merchantCode, tenantCod);
        if (deviceDOList == null || deviceDOList.isEmpty()) {
            return Result.success(new ArrayList<>());
        }
        return Result.success(deviceDOList.stream().map(t -> new SimpleEntityVO(t.getCode(), t.getNumber(), t.getName())).collect(Collectors.toList()));
    }

    @Override
    /**
     * 获取设备详情（提供给app配置使用）
     *
     * @param deviceId
     * @return
     */
    public Result<DeviceAppDetailVO> getDetail4App(String deviceId) {
        DeviceDO deviceDO = deviceService.getByDeviceId(deviceId);
        if (deviceDO == null) {
            throw new BizException(ResultCodeEnum.NOT_EXISTS_DATA_FAILED, "不存在设备");
        }
        NoticeRuleParameterDO noticeRuleParameterDO = noticeRuleService.getDeviceNoticeRuleParameter(deviceDO.getCode(),
                DictionariesConstant.INSTANCE.getSystemDeviceNoticeRuleName(), DictionariesConstant.INSTANCE.getSystemDeviceNoticeParameterName());
        DeviceAppDetailVO deviceAppDetailVO = new DeviceAppDetailVO();
        if (noticeRuleParameterDO == null || StringUtils.isBlank(noticeRuleParameterDO.getParameterValue())) {
            deviceAppDetailVO.setDeviceTemperature(DictionariesConstant.INSTANCE.getSystemDefaultNoticeTemp());
        } else {
            deviceAppDetailVO.setDeviceTemperature(Double.parseDouble(noticeRuleParameterDO.getParameterValue()));
        }
        deviceAppDetailVO.setUploadRecordPath(DictionariesConstant.INSTANCE.getDwUploadDataApi());
        List<UserDO> userDOList = userService.getDeviceRelationUsers(deviceDO.getCode());
        if (userDOList == null || userDOList.isEmpty()) {
            deviceAppDetailVO.setUserList(new ArrayList<>());
            return Result.success(deviceAppDetailVO);
        }
        List<UserAppDetailVO> userList = new ArrayList<>();
        for (UserDO userDO : userDOList) {
            if (StringUtils.isBlank(userDO.getFaceImgUrl()) || UserStateEnum.disabled.getValue().equalsIgnoreCase(userDO.getState())) {
                continue;
            }
            JSONArray faceImgList = JSONArray.parseArray(userDO.getFaceImgUrl());
            UserAppDetailVO userAppDetailVO = new UserAppDetailVO(userDO.getCode(), userDO.getPhone(), userDO.getNumber());
            userAppDetailVO.setFaceUrl((String) faceImgList.get(0));
            userList.add(userAppDetailVO);
        }
        deviceAppDetailVO.setUserList(userList);
        return Result.success(deviceAppDetailVO);
    }

    @Override
    /**
     * 获取设备app更新信息
     * @param deviceId
     * @return
     */
    public Result<JSONObject> getDeviceUpdateInfo(String deviceId) {
        DeviceDO deviceDO = deviceService.getByDeviceId(deviceId);
        if (deviceDO == null) {
            return Result.success(new JSONObject());
        }
        AppUpdateInfoVO appUpdateInfoVO = merchantService.getAppUpdateInfoVO(deviceDO.getMerchantCode(), deviceDO.getTenantCode());
        if (appUpdateInfoVO == null) {
            return Result.success(new JSONObject());
        }
        LocalDateTime now = LocalDateTime.now();
        int nowHour = now.getHour();
        if (nowHour >= appUpdateInfoVO.getStartTime() && nowHour <= appUpdateInfoVO.getEndTime()) {
            JSONObject values = JSONObject.parseObject(JSONObject.toJSONString(appUpdateInfoVO));
            return Result.success(values);
        }
        return Result.success(new JSONObject());
    }

    @Override
    /**
     * 上传记录
     *
     * @param personnelId
     * @param deviceId
     * @param time
     * @param temperature
     * @param fileUrl
     * @return
     */
    public Boolean saveRecordResult(String personnelId, String deviceId, LocalDateTime time, Double temperature, String fileUrl) {
        DeviceDO deviceDO = deviceService.getByDeviceId(deviceId);
        if (deviceDO == null) {
            //非自有设备忽略
            return true;
        }
        NoticeRuleParameterDO noticeRuleParameterDO = noticeRuleService.getDeviceNoticeRuleParameter(deviceDO.getCode(),
                DictionariesConstant.INSTANCE.getSystemDeviceNoticeRuleName(), DictionariesConstant.INSTANCE.getSystemDeviceNoticeParameterName());
        Double noticeTemperature = Double.parseDouble("0");
        if (noticeRuleParameterDO == null || StringUtils.isBlank(noticeRuleParameterDO.getParameterValue())) {
            noticeTemperature = DictionariesConstant.INSTANCE.getSystemDefaultNoticeTemp();
        } else {
            noticeTemperature = Double.parseDouble(noticeRuleParameterDO.getParameterValue());
        }
        temperature = BigDecimal.valueOf(temperature).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        RecordDO recordDO = new RecordDO();
        recordDO.initForNew(DictionariesConstant.INSTANCE.getDefaultUserCode());
        recordDO.setProduceTime(time);
        recordDO.setDeviceCode(deviceDO.getCode());
        recordDO.setUserCode(personnelId);
        recordDO.setRecordResult(temperature.toString());
        recordDO.setRecordImages(fileUrl);
        if (noticeTemperature < temperature && personnelId != null) {
            recordDO.setState(DeviceUploadDataStateEnum.exception.getValue());
            //异步邮件通知
            CompletableFuture<Boolean> futureLog = CompletableFuture.supplyAsync(() ->
                    noticeBizService.noticeToUsers(deviceDO, recordDO)
            );
        } else if (noticeTemperature < temperature && personnelId == null) {
            recordDO.setState(DeviceUploadDataStateEnum.unknown_user_exception.getValue());
            //异步邮件通知
            CompletableFuture<Boolean> futureLog = CompletableFuture.supplyAsync(() ->
                    noticeBizService.noticeToUsers(deviceDO, recordDO)
            );
        } else if (personnelId == null) {
            recordDO.setState(DeviceUploadDataStateEnum.unknown_user.getValue());
            //异步邮件通知
            CompletableFuture<Boolean> futureLog = CompletableFuture.supplyAsync(() ->
                    noticeBizService.noticeToUsers(deviceDO, recordDO)
            );
        } else {
            recordDO.setState(DeviceUploadDataStateEnum.normal.getValue());
        }
        if (deviceService.addRecord(recordDO)) {
            return true;
        }
        return false;
    }

    @Override
    /**
     *  验证设备存在
     *
     *
     * @param deviceId 设备id
     * @return
     */
    public Boolean checkExistDeviceId(String deviceId) {
        DeviceDO deviceDO = deviceService.getByDeviceId(deviceId);
        if (deviceDO == null) {
            //非自有设备忽略
            return false;
        }
        return true;
    }


}
